package com.streambolics.std;

import java.lang.reflect.Method;

/**
 * An object capable of dynamically invoke methods in a target object.
 * 
 * @author Sauron
 * 
 */

public class Invoker
{
    private final Object _target;

    /**
     * Creates an invoker for the given target.
     * 
     * @param aTarget
     *            The target object.
     */

    public Invoker(Object aTarget)
    {
        _target = aTarget;
    }

    private Method getMethod (String aMethodName, Class<?> aClass)
    {
        try
        {
            return _target.getClass ().getMethod (aMethodName, aClass);
        }
        catch (NoSuchMethodException e)
        {
            return null;
        }
    }

    /**
     * Invokes the named parameterless method of the target.
     * 
     * @param aMethodName
     *            The simple name of the method to call.
     * @throws Exception
     *             As per Streambolics Core convention.
     */

    public void invoke (String aMethodName) throws Exception
    {
        Method m = _target.getClass ().getMethod (aMethodName);
        m.invoke (_target);
    }

    public void invoke (String aMethodName, double aArg1) throws Exception
    {
        Method m = _target.getClass ().getMethod (aMethodName, Double.class);
        m.invoke (_target, aArg1);
    }

    public void invoke (String aMethodName, int aArg1) throws Exception
    {
        Method m = _target.getClass ().getMethod (aMethodName, Integer.class);
        m.invoke (_target, aArg1);
    }

    public void invoke (String aMethodName, String aArg1) throws Exception
    {
        Method m = _target.getClass ().getMethod (aMethodName, String.class);
        m.invoke (_target, aArg1);
    }

    public void invoke (String aMethodName, String aArg1, String aArg2) throws Exception
    {
        Method m = _target.getClass ().getMethod (aMethodName, String.class, String.class);
        m.invoke (_target, aArg1, aArg2);
    }

    /**
     * Sets the value of a JavaBean property from a string representation.
     * 
     * This method is useful for parsing the serialized representation of an
     * object's properties.
     * 
     * @param aBean
     *            The name of the bean property.
     * @param aArg
     *            The string representation of the value to assign. The value
     *            will be converted as needed to an integer or to a floating
     *            point value.
     * @return True if the property has been found and assigned to, false if the
     *         property was not found.
     * @throws Exception
     *             As per Streambolics Core convention. Exceptions are thrown in
     *             there was an error in the property setter, or the value could
     *             not be converted.
     */

    public boolean invokeDynamicSetter (String aBean, String aArg) throws Exception
    {
        if (aArg == null)
        {
            return true;
        }

        String methodName = "set" + aBean;

        Method m = getMethod (methodName, String.class);
        if (m != null)
        {
            m.invoke (_target, aArg);
            return true;
        }

        m = getMethod (methodName, Integer.class);
        if (m != null)
        {
            m.invoke (_target, Integer.parseInt (aArg));
            return true;
        }

        m = getMethod (methodName, Integer.TYPE);
        if (m != null)
        {
            m.invoke (_target, Integer.parseInt (aArg));
            return true;
        }

        m = getMethod (methodName, Double.class);
        if (m != null)
        {
            m.invoke (_target, Double.parseDouble (aArg));
            return true;
        }

        m = getMethod (methodName, Double.TYPE);
        if (m != null)
        {
            m.invoke (_target, Double.parseDouble (aArg));
            return true;
        }

        return false;
    }

    public boolean invokeOptional (String aMethodName) throws Exception
    {
        try
        {
            invoke (aMethodName);
            return true;
        }
        catch (NoSuchMethodException e)
        {
            return false;
        }
    }

    public boolean invokeOptional (String aMethodName, String aArg1) throws Exception
    {
        try
        {
            invoke (aMethodName, aArg1);
            return true;
        }
        catch (NoSuchMethodException e)
        {
            return false;
        }
    }

    public boolean invokeOptional (String aMethodName, String aArg1, String aArg2) throws Exception
    {
        try
        {
            invoke (aMethodName, aArg1, aArg2);
            return true;
        }
        catch (NoSuchMethodException e)
        {
            return false;
        }
    }
}
